package cn.edu.hitsz.compiler.lexer;

import cn.edu.hitsz.compiler.NotImplementedException;
import cn.edu.hitsz.compiler.symtab.SymbolTable;
import cn.edu.hitsz.compiler.utils.FilePathConfig;
import cn.edu.hitsz.compiler.utils.FileUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.stream.StreamSupport;

/**
 * TODO: 实验一: 实现词法分析
 * <br>
 * 你可能需要参考的框架代码如下:
 *
 * @see Token 词法单元的实现
 * @see TokenKind 词法单元类型的实现
 */
public class LexicalAnalyzer {
    private final SymbolTable symbolTable;
    //自动机状态：起始、词语（包含id与关键字）、数字、符号
    public enum State{
        START,ID,NUM,SIGN
    }
    //按行保存读入的待分析代码
    private List<String> lines;
    //保存分析结果token表
    private List<Token>  list;

    public LexicalAnalyzer(SymbolTable symbolTable) {
        this.symbolTable = symbolTable;
    }



    /**
     * 从给予的路径中读取并加载文件内容
     *
     * @param path 路径
     */
    public void loadFile(String path) {
        // TODO: 词法分析前的缓冲区实现
        // 可自由实现各类缓冲区
        // 或直接采用完整读入方法
        lines = FileUtils.readLines(FilePathConfig.SRC_CODE_PATH);
    }



    /**
     * 执行词法分析, 准备好用于返回的 token 列表 <br>
     * 需要维护实验一所需的符号表条目, 而得在语法分析中才能确定的符号表条目的成员可以先设置为 null
     */
    public void run() {
        //TODO: 自动机实现的词法分析过程
        list = new ArrayList<>();//对错误输入处理能力有限
        for(String line:lines){
            char[] cur = line.toCharArray();
            State state = State.START;//自动机设为起始状态
            StringBuilder str = new StringBuilder();
            int idx = 0;//遍历每行所有字符的索引
            //依次读入字符，将判定完成的字符串录入List<Token>
            while(idx < cur.length){
                switch (state){
                    case START:
                        if(Character.isDigit(cur[idx])){
                            state = State.NUM;
                            str.append(cur[idx++]);
                        }else if(Character.isAlphabetic(cur[idx])){
                            state = State.ID;
                            str.append(cur[idx++]);
                        }else if(cur[idx]==' '){
                            idx ++;
                        } else {
                            state = State.SIGN;
                            str.append(cur[idx]);
                        }
                        break;
                    case NUM:
                        if(!Character.isDigit(cur[idx])){
                            list.add(Token.normal("IntConst",str.toString()));
                            state = State.START;
                            str.delete(0,str.length());
                        }else {
                            str.append(cur[idx++]);
                        }
                        break;
                    case ID:
                        if(Character.isAlphabetic(cur[idx]) || Character.isDigit(cur[idx])){
                            str.append(cur[idx++]);
                        }else {
                            String temp = str.toString();
                            //区分关键字与id
                            if(temp.equals("int")||temp.equals("return")){
                                list.add(Token.simple(temp));
                            }else {
                                list.add(Token.normal("id",temp));
                                //录入符号表
                                if (!symbolTable.has(temp)) {
                                    symbolTable.add(temp);
                                }
                            }
                            state = State.START;
                            str.delete(0,str.length());
                        }
                        break;
                    case SIGN:
                        //由于只有长度为1的符号，读到即可录入，故对于符号不做分别处理
                        String temp = str.toString();
                        if (!temp.equals(";")) {
                            list.add(Token.simple(temp));
                        }else {
                            list.add(Token.simple("Semicolon"));
                        }
                        idx ++;
                        state = State.START;
                        str.delete(0,str.length());
                        break;
                }
            }
        }
        list.add(Token.eof());
    }

    /**
     * 获得词法分析的结果, 保证在调用了 run 方法之后调用
     *
     * @return Token 列表
     */
    public Iterable<Token> getTokens() {
        // TODO: 从词法分析过程中获取 Token 列表
        // 词法分析过程可以使用 Stream 或 Iterator 实现按需分析
        // 亦可以直接分析完整个文件
        // 总之实现过程能转化为一列表即可
        return this.list;
    }

    public void dumpTokens(String path) {
        FileUtils.writeLines(
                path,
                StreamSupport.stream(getTokens().spliterator(), false).map(Token::toString).toList()
        );
    }

}
